/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       beastmaster_hut.cpp

	$Header: /game/beastmaster_hut.cpp $

	$NoKeywords: $

 ************************************************************************/
// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "beastmaster_hut.h"

#include "adventure_frame.h"
#include "adventure_map.h"
#include "adventure_sounds.h"
#include "ai_value.h"
#include "army.h"
#include "basic_dialog.h"
#include "creature_array.h"
#include "dialog_beastmaster.h"
#include "enum_operations.h"
#include "hero.h"
#include "dialog_magic_university.h"
#include "mouse_event.h"
#include "music.h"
#include "object_registration.h"
#include "player.h"
#include "popup_window.h"
#include "random.h"
#include "replace_keywords.h"
#include "select_skill_from_set.h"
#include "simple_dialog.h"
#include "skill.h"
#include "skill_set.h"

namespace
{
	int const k_current_map_format_version = 1;
	t_object_registration<t_beastmaster_hut> k_registration( k_adv_object_school, 
															 k_school_beastmasters_hut );
	t_object_registration<t_witch_hut>       k_witch_registration( k_adv_object_school, 
																   k_school_witchs_hut );
}

// ------------------------------------------------------------------------
// learn a primary skill
// ------------------------------------------------------------------------
t_beastmaster_hut::t_beastmaster_hut( t_stationary_adventure_object const& source )
                 : t_stationary_adventure_object( source ),
				   m_available_skills( ~t_skill_set() ),
				   m_skill( k_skill_none )
{
}

// ------------------------------------------------------------------------
// learn a primary skill
// ------------------------------------------------------------------------
void t_beastmaster_hut::show_dialog( std::string const& text, t_level_map_point_2d point )
{
	t_counted_ptr<t_basic_dialog> basic_dialog;

	basic_dialog = new t_basic_dialog;
	basic_dialog->set_text( replace_keywords( text, m_skill, k_mastery_basic ) );
	basic_dialog->add_skill( t_skill( m_skill, k_mastery_basic ));
	basic_dialog->add_ok_button();
	basic_dialog->open( get_dialog_bottom( point ), true, k_align_bottom );
	basic_dialog->run_modal();
}

// ------------------------------------------------------------------------
// learn a primary skill
// ------------------------------------------------------------------------
void t_beastmaster_hut::activate_trigger( t_army* army, t_adv_map_point const& point, 
		                                  t_direction direction, t_adventure_frame* frame )
{
	int				     i;
	int                  hero_count = 0;
	t_creature_array&    creatures = army->get_creatures();
	t_hero*              hero;
	bool                 knows_skill = false;
	std::vector<t_hero*> students;
	std::vector<t_hero*> learned_students;
	std::string          text;

	// determine who can learn the skill
	int owner_number = army->get_owner_number();
	if (owner_number >= 0)
		m_visited[owner_number] = true;
	else
		return; // A gray army shouldn't activate us, but if it does... bail.

	// Handle the AI army
	t_player* player = army->get_owner();
	if (player->is_computer())
	{
		for (i = 0; i < t_creature_array::k_size; i++)
		{
			hero = creatures[i].get_hero();
			if ( !hero || 
					(hero->get_primary_skill_count() >= k_primary_skill_limit) || 
					(hero->get_skill( m_skill ) >= k_mastery_basic) )
				continue;
			
			if (ai_wants_primary_skill(hero, m_skill, army))
			{
				hero->learn_skill( t_skill( m_skill, k_mastery_basic) );
				hero->update_class();
			}
		}
		
		return;
	}

	// Handle the human player
	bool                    dead_heroes = true;
	bool                    any_heroes = false;
	for (i = 0; i < t_creature_array::k_size; i++)
	{
		hero = creatures[i].get_hero();
		if (hero == 0)
			continue;
        any_heroes = true;
        if (hero->is_dead())
			continue;
	    dead_heroes = false;
		students.push_back( hero );
		if (hero->get_skill( m_skill ) > k_mastery_none)
			knows_skill = true;
		else if (hero->get_primary_skill_count() < k_primary_skill_limit)
			hero_count++;
	}

    if (!any_heroes)
    {
		ok_dialog( get_text("no_heroes"), get_dialog_bottom(point) );
        return;
    }
    if (dead_heroes)
    {
		ok_dialog( get_text("dead_heroes"), get_dialog_bottom(point) );
        return;
    }

	if (hero_count == 0)
	{
		if (knows_skill)
			show_dialog( get_text("already_known"), point );
		else
			show_dialog( get_text("cannot_learn"), point );
		return;
	}

	t_counted_ptr<t_dialog_beastmaster> dialog;

	dialog = new t_dialog_beastmaster( students, m_skill, get_text("initial"), frame, *this );
	t_sound_cache music = get_music_playing();
	stop_music();
	get_dialog_sound( k_dialog_sound_university )->play( get_sound_volume() );
	if (!dialog->run_modal())
	{
		play_music( music );
		return;
	}

	play_music( music );

	learned_students = dialog->get_selected_heroes();

	//show_dialog( get_text("accept" ), point );
    display_skill( t_skill( m_skill, k_mastery_basic ), frame, learned_students, 
                    replace_keywords( get_text("accept"), m_skill, k_mastery_basic ));
}

// ------------------------------------------------------------------------
// learn a primary skill
// ------------------------------------------------------------------------
std::string t_beastmaster_hut::get_balloon_help() const
{
	if (!m_visited[get_map()->get_player_number()])
		return get_name();
	return replace_keywords( get_text( "name_visited" ), m_skill, k_mastery_basic );
}

// ------------------------------------------------------------------------
// learn a primary skill
// ------------------------------------------------------------------------
void t_beastmaster_hut::right_click( t_mouse_event const& event,
	                                 t_adventure_frame* adventure_frame )
{
	t_skill_mastery information = get_information_level();
	int				player_number = get_map()->get_player_number();

	if (information >= k_mastery_basic)
		m_visited[player_number] = true;

	if (!m_visited[player_number])
	{
		t_stationary_adventure_object::right_click( event, adventure_frame );
		return;
	}

	std::string text;

	text = get_text("help_visited" );
	text = replace_keywords( text, m_skill, k_mastery_basic );

	t_window*					  window;
	t_window*					  modal_window = t_window::get_main_window();
	t_screen_point                point = event.screen_point;
	t_counted_ptr<t_basic_dialog> dialog;

	point = modal_window->to_client( point );
	window = new t_popup_window( point, modal_window );
	window->set_cursor( adventure_frame->get_cursor( false ));
	dialog = new t_basic_dialog( window );
	dialog->add_skill( t_skill( m_skill, k_mastery_basic ));

	assert( !text.empty() );
	text[0] = toupper( text[0] );
	dialog->set_text( text );
	dialog->open( t_screen_point(0,0), modal_window->get_client_rect() - point, 
		          true, k_align_top );
	window->fit_to_parent_rect();
}


// ------------------------------------------------------------------------
// Default available skills for old maps
// ------------------------------------------------------------------------
t_skill_set const & t_beastmaster_hut::get_default_available_skill_set()
{
	return ::get_skill_set(true, false, false, true);
}

// ------------------------------------------------------------------------
// learn a primary skill
// ------------------------------------------------------------------------
int t_beastmaster_hut::get_version() const
{
	return 1;
}

// ------------------------------------------------------------------------
// learn a primary skill
// ------------------------------------------------------------------------
bool t_beastmaster_hut::read( std::streambuf&						stream, 
						      t_qualified_adv_object_type const&	type,
						      int									version )
{
	if (version < 1)
	{
		m_skill = k_skill_none; // Resolve in place()
		m_available_skills = get_default_available_skill_set();
		m_required_skills.reset();
		return true;
	}
	m_skill = t_skill_type( get<t_uint8>( stream ));
	return m_visited.read( stream );
}

// ------------------------------------------------------------------------
// learn a primary skill
// ------------------------------------------------------------------------
bool t_beastmaster_hut::read_from_map( std::streambuf& stream, t_progress_handler* progress )
{
	int version = get< t_uint16 >( stream );
	if ( version < 0 || version > k_current_map_format_version )
		return false;

	m_skill = k_skill_none; // Resolve in place()

	if (version >= 1)
	{
		if (!m_available_skills.read( stream ) ||
			!m_required_skills.read( stream ))
		{
			return false;
		}
	}
	else
	{
		m_available_skills = get_default_available_skill_set();
		m_required_skills.reset();
	}


	return true;
}

// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
void t_beastmaster_hut::place( t_adventure_map& map, t_adv_map_point const & point )
{
	t_stationary_adventure_object::place( map, point );

	if ( m_skill == k_skill_none )
	{
		// Choose skill. We can't do this in read_from_map() since we don't have
		// the map's list of allowed skills yet
		t_skill_set available_skills = m_available_skills & map.get_allowed_skills();

		if ( available_skills.none() )
		{
			available_skills = m_available_skills;
			if ( available_skills.none() )
			{
				available_skills = map.get_allowed_skills();
				if ( available_skills.none() )
				{
					available_skills = get_default_available_skill_set();
				}
			}
		}

		m_skill = select_skill_from_set(available_skills, m_required_skills);
	}
}

// ------------------------------------------------------------------------
// learn a primary skill
// ------------------------------------------------------------------------
bool t_beastmaster_hut::write( std::streambuf& stream ) const
{
	put<t_uint8>( stream, m_skill );
	return m_visited.write( stream );
}

// ------------------------------------------------------------------------
// learn a primary skill
// ------------------------------------------------------------------------
float t_beastmaster_hut::ai_value( t_adventure_ai const& ai, t_creature_array const& army, int move_cost ) const
{
	if (m_visited[get_player_number(army)])
	{
		t_skill skill( m_skill, k_mastery_basic);
		float value = 0.0f;
		for (int i = 0; i < t_creature_array::k_size; i++) 
		{
			t_hero const* hero  = army[i].get_const_hero();
			if ( !hero || 
					(hero->get_primary_skill_count() >= k_primary_skill_limit) || 
					(hero->get_skill( m_skill ) >= k_mastery_basic) ||
					!ai_wants_primary_skill( hero, m_skill, &army)
					)
				continue;

			value += ai_value_of_skill_increase( hero, skill, &army );
		}
		return value;
	} else 
		return ai_summed_primary_skill_value( 0, true, &army );
}

// ------------------------------------------------------------------------
// learn a primary skill
// ------------------------------------------------------------------------
t_witch_hut::t_witch_hut( t_stationary_adventure_object const& source )
           : t_beastmaster_hut( source )
{
}

// ------------------------------------------------------------------------
// Default available skills for old maps
// ------------------------------------------------------------------------
t_skill_set const & t_witch_hut::get_default_available_skill_set()
{
	return ::get_skill_set(true, false, true, false);
}


